Remix Action 與 Loader 一樣是伺服器端運行的程式碼,一樣可以取得 { request, params }。不同的地方只有名字跟 Method 是 POST、PUT、DELETE。Remix V1 是可以自訂 Method 的(就是定義除了 POST、PUT、DELETE 之外的方法),V2 就拿掉了。
ref: Remix Action
小提醒:在寫 type 的時候要記得 return 的東西要一致,不然前端的 actionData 會有很多版本很難搞。
// /app/route/user.tsx
// 後端程式碼 1. 確認使用者 session 2. 返回
export const action = async({ request, params }) => {
const session = await getSession(request)
if (!session) {
// 這個 flash 可以在下個 route 讀取 session 並 commit 後自動消失,記得讀取後也要 commit Session 不然 flash 不會消失
session.flash('errorMessage', ['請先登入再執行操作', 'Additional Info'])
return redirect('/signin', {
headers: {
Set-Cookie: await commit Session(request)
}
})
}
if (request.method === 'PUT') {
try {
const result = await db.updateUserData(session)
return json({ data: result, msg: 'Success updated user data', error: null })
} catch (error) {
console.error('Error in /user action', error)
throw new Response('Internal error', 500)
}
} else {
throw new Response('Method not allowed', 405)
}
}
// 前端程式碼
export default function User() {
// 我省略 loader function,請見上篇
const { user } = useLoaderData<typeof loader>()
// 使用方法與 laoder 一樣,不過無法直接解構,因為一進來時 actionData 會是 undefined
const actionData = useLoaderData<typeof action>()
// 如果你是使用 Remix 的 Form,因為頁面不會重新載入,因此要使用 useEffect 聆聽 actionData 的變動
useEffect(() => {
if (actionData) alert(actionData.msg)
}, [actionData])
return (
<></>
)
}
Form 是 Remix 的一個方便的 Component,如果是寫在同一個 route 下(也就是同個文件上面就是 action),可以在 Form 的地方省略指定 action 的位置,Remix 會自己找,不過如果你是在 _index
的 route 提交的,因為這個文件本身沒有建立 route,所以提交的位置是當個 /route?index。
ref: Index Query Param、Form
export default function Frontend() {
const { user } = useLoaderData<typeof loader>();
return (
<div>
<h3>{user.name}</h3>
<Form method="post" action={'/user'}>
<input type="text" name="name" />
<button type="submit">Edit Name</button>
</Form>
</div>
);
}
Submit 是來自 useSubmit()
hook,是當你在提交 input 資料前,需要做些處理時會用到的。
import { useSubmit } from '@remix-run/react'
{...}
export default function Whatever() {
const submit = useSubmit()
{...}
<Form
onSubmit={e => {
const form = e.currentTarget
// 處理 form
submit(form, {
method: 'PUT',
, encType: 'application/json', // submit 預設是使用 FormData,如果要以 JSON 傳送要設定這個
navigate: false, // navigate 可以決定提交表單之後要不要跳轉
...otherOptions
})
}}
{...}
}
Fetcher 的話適用於你要提交表單但不想跳轉,來自 useFetcher()
hook,這個是我後來最常用到的 hook,他的 fetcher.submit() 就是跟上面的 submit 運作方式一樣,不過你可以取得 submit 後 route 返回的資料!這個對 Optimistic UI(使用者點了就先顯示,如果 DB 錯誤再顯示給使用者)非常有用!
不過不確定 submit 現在是不是也可以取得 route 返回的資料(看看下面 ref Sma Selicoff 的影片),不過官方都是用 fetcher。
Fetcher 剛開始接觸可能會有點難理解,以下的 ref 可以多看看!Remix Single 我斷斷續續看了有 20 次哈哈哈
ref: Remix Optimistic UI、Remix Single: Optimistic UI - Remix、Optimistic UI in Remix - Sam Selikoff